﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using AzukiMap.Layer;
using AzukiMap.Map;
using AzukiMap.MapSource;
using AzukiMap.Tools.Logger;
using GisSharpBlog.NetTopologySuite.IO;

[assembly: InternalsVisibleTo("TestAzukiMapSL.Request")]
namespace AzukiMap.Request
{
    public class PostGisVectorRequest : HttpGetRequest
    {
        const string EXPRESSION_SEP_CHAR = "<->";
        const string ATTRIBUTES_SEP_CHAR = ",";

        private readonly NumberFormatInfo _nfi = new NumberFormatInfo() {NumberDecimalSeparator = "."};
        
        //protected VectorLayer _layer;
        protected PostGisLayer _layer;
        protected string _currentExtentWkt;
        protected string _previousExtentWkt;
        protected Dictionary<string, string> _params;
        protected WKTWriter _wktWriter;
        protected int _srid;
        protected double _tolerance;

        public PostGisLayer VectorLayer
        {
            get { return _layer; }
            set { _layer = value; }
        }

        public PostGisVectorRequest(PostGisLayer layer)
            : base(AzukiMapSettings.DEFAULT_GETPOSTGISDATA_URI)
        {
            Logger.Debug(
                "PostGisVectorRequest.PostGisDataRequest(2):"
                + " vectorLayer.Name = " + layer.LayerName
                );

            init(layer);
        }

        public PostGisVectorRequest(PostGisLayer layer, string getColumnDataUri)
            : base(getColumnDataUri)
        {
            Logger.Debug(
                "PostGisVectorRequest.PostGisDataRequest(3):"
                + " vectorLayer.Name = " + layer.LayerName
                );

            init(layer);
        }

        protected void init(PostGisLayer layer)
        {
            _wktWriter = new WKTWriter();
            _params = new Dictionary<string, string>();
            VectorLayer = layer;
        }

        protected void SetMapParams()
        {
            if (_layer != null)
            {
                _srid = _layer.MapCoord.Srid;
                _tolerance = _layer.MapCoord.Tolerance * (_layer.MapCoord.InchesPerUnit / _layer.MapSource.InchesPerUnit );
                _currentExtentWkt = _wktWriter.Write(_layer.CurrentExtent);
                //_previousExtentWkt = _wktWriter.Write(_mapCoord.LastExtent);
                if (_layer.RenderedExtent != null)
                {
                    _previousExtentWkt = _wktWriter.Write(_layer.RenderedExtent);
                }
                else
                {
                    _previousExtentWkt = "";
                }
            }
        }

        internal override void SetRequestParams()
        {
            SetMapParams();
            try
            {
                string expressions = CreateExpressionString();
                string attributes = CreateAttributesString();
                _params["table"] = _layer.PgSource.TableName;
                _params["column"] = _layer.PgSource.GeometryColumn;
                _params["db"] = _layer.PgSource.DbName;
                _params["cr"] = _currentExtentWkt;
                _params["pr"] = _previousExtentWkt;
                _params["exs"] = expressions;
                _params["ats"] = attributes;
                _params["tolerance"] = _tolerance.ToString(_nfi);
                _params["srid"] = _srid.ToString();
                _params["tsrid"] = _layer.PgSource.Srid.ToString();
                _params["f"] = _layer.PgSource.Where;
            }
            catch (ArgumentNullException ex)
            {
                Logger.Error("MapStatus or LayerStatus may be null.", ex);
            }
            catch (Exception ex)
            {
                Logger.Error("Something wrong to create a request params.", ex);
            }

            RequestParams = _params;

            Logger.Debug(
                "PostGisDataRequest.SetRequestParams(): "
                + " RequstParams = " + RequestParams.ToString()
                );
        }

        string CreateExpressionString()
        {
            return GetListString(_layer.Expressions, EXPRESSION_SEP_CHAR);
        }

        string CreateAttributesString()
        {
            return GetListString(_layer.Labels, ATTRIBUTES_SEP_CHAR);
        }

        string GetListString(IEnumerable<String> list, string separateChar) 
        {
            string listStr = "";
            if (list != null)
            {
                bool isFirst = true;
                foreach (string str in list)
                {
                    if (isFirst)
                    {
                        isFirst = false;
                    }
                    else
                    {
                        listStr += separateChar;
                    }
                    listStr += str;
                }
            }
            return listStr;
        }

    }
}
